/**
 * Copyright 2020-2023 the original author or Linlan authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.linlan.commons.core;

import net.linlan.commons.core.lang.Assert;
import net.linlan.commons.core.lang.BasicType;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * The ConvertUtils class provides utility methods for converting objects from one type to another.
 * It handles various data types and provides default values in case of conversion failure.
 *
 * @since 1.0
 * @version 1.0
 */
public final class ConvertUtils {

    /**
     * Private constructor to prevent instantiation of this utility class.
     */
    private ConvertUtils() {
    }

    /**
     * Converts the given source object to a String.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted String, or the default value if conversion fails.
     */
    public static String toStr(Object source, String defValue) {
        return convert(String.class, source, defValue);
    }

    /**
     * Converts the given source object to a String.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted String, or null if conversion fails.
     */
    public static String toStr(Object source) {
        return toStr(source, null);
    }

    /**
     * Converts the given source object to a Character.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Character, or the default value if conversion fails.
     */
    public static Character toChar(Object source, Character defValue) {
        return convert(Character.class, source, defValue);
    }

    /**
     * Converts the given source object to a Character.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Character, or null if conversion fails.
     */
    public static Character toChar(Object source) {
        return toChar(source, null);
    }

    /**
     * Converts the given source object to a Byte.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Byte, or the default value if conversion fails.
     */
    public static Byte toByte(Object source, Byte defValue) {
        return convert(Byte.class, source, defValue);
    }

    /**
     * Converts the given source object to a Byte.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Byte, or null if conversion fails.
     */
    public static Byte toByte(Object source) {
        return toByte(source, null);
    }

    /**
     * Converts the given source object to a Short.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Short, or the default value if conversion fails.
     */
    public static Short toShort(Object source, Short defValue) {
        return convert(Short.class, source, defValue);
    }

    /**
     * Converts the given source object to a Short.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Short, or null if conversion fails.
     */
    public static Short toShort(Object source) {
        return toShort(source, null);
    }

    /**
     * Converts the given source object to a Number.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Number, or the default value if conversion fails.
     */
    public static Number toNumber(Object source, Number defValue) {
        return convert(Number.class, source, defValue);
    }

    /**
     * Converts the given source object to a Number.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Number, or null if conversion fails.
     */
    public static Number toNumber(Object source) {
        return toNumber(source, null);
    }

    /**
     * Converts the given source object to an Integer.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Integer, or the default value if conversion fails.
     */
    public static Integer toInt(Object source, Integer defValue) {
        return convert(Integer.class, source, defValue);
    }

    /**
     * Converts the given source object to an Integer.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Integer, or null if conversion fails.
     */
    public static Integer toInt(Object source) {
        return toInt(source, null);
    }

    /**
     * Converts the given source object to an array of Integer.
     *
     * @param source The object to be converted.
     * @return The converted array of Integer.
     */
    public static Integer[] toIntArray(Object source) {
        return convert(Integer[].class, source);
    }

    /**
     * Converts the given source object to a Long.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Long, or the default value if conversion fails.
     */
    public static Long toLong(Object source, Long defValue) {
        return convert(Long.class, source, defValue);
    }

    /**
     * Converts the given source object to a Long.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Long, or null if conversion fails.
     */
    public static Long toLong(Object source) {
        return toLong(source, null);
    }

    /**
     * Converts the given source object to an array of Long.
     *
     * @param source The object to be converted.
     * @return The converted array of Long.
     */
    public static Long[] toLongArray(Object source) {
        return convert(Long[].class, source);
    }

    /**
     * Converts the given source object to a Double.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Double, or the default value if conversion fails.
     */
    public static Double toDouble(Object source, Double defValue) {
        return convert(Double.class, source, defValue);
    }

    /**
     * Converts the given source object to a Double.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Double, or null if conversion fails.
     */
    public static Double toDouble(Object source) {
        return toDouble(source, null);
    }

    /**
     * Converts the given source object to an array of Double.
     *
     * @param source The object to be converted.
     * @return The converted array of Double.
     */
    public static Double[] toDoubleArray(Object source) {
        return convert(Double[].class, source);
    }

    /**
     * Converts the given source object to a Float.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Float, or the default value if conversion fails.
     */
    public static Float toFloat(Object source, Float defValue) {
        return convert(Float.class, source, defValue);
    }

    /**
     * Converts the given source object to a Float.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Float, or null if conversion fails.
     */
    public static Float toFloat(Object source) {
        return toFloat(source, null);
    }

    /**
     * Converts the given source object to an array of Float.
     *
     * @param source The object to be converted.
     * @return The converted array of Float.
     */
    public static Float[] toFloatArray(Object source) {
        return convert(Float[].class, source);
    }

    /**
     * Converts the given source object to a Boolean.
     * String values supported are: "true", "false", "yes", "ok", "no", "1", "0".
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted Boolean, or the default value if conversion fails.
     */
    public static Boolean toBool(Object source, Boolean defValue) {
        return convert(Boolean.class, source, defValue);
    }

    /**
     * Converts the given source object to a Boolean.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted Boolean, or null if conversion fails.
     */
    public static Boolean toBool(Object source) {
        return toBool(source, null);
    }

    /**
     * Converts the given source object to an array of Boolean.
     *
     * @param source The object to be converted.
     * @return The converted array of Boolean.
     */
    public static Boolean[] toBooleanArray(Object source) {
        return convert(Boolean[].class, source);
    }

    /**
     * Converts the given source object to a BigInteger.
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted BigInteger, or the default value if conversion fails.
     */
    public static BigInteger toBigInteger(Object source, BigInteger defValue) {
        return convert(BigInteger.class, source, defValue);
    }

    /**
     * Converts the given source object to a BigInteger.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted BigInteger, or null if conversion fails.
     */
    public static BigInteger toBigInteger(Object source) {
        return toBigInteger(source, null);
    }

    /**
     * Converts the given source object to a BigDecimal
     * (原注释未完整，这里假设需要补齐注释，可按需修改)
     * If the source is null or the conversion fails, the default value is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source   The object to be converted.
     * @param defValue The default value to return if the conversion fails.
     * @return The converted BigDecimal, or the default value if conversion fails.
     */
    public static BigDecimal toBigDecimal(Object source, BigDecimal defValue) {
        return convert(BigDecimal.class, source, defValue);
    }

    /**
     * Converts the given source object to a BigDecimal.
     * If the source is null or the conversion fails, null is returned.
     * Conversion failures do not throw an exception.
     *
     * @param source The object to be converted.
     * @return The converted BigDecimal, or null if conversion fails.
     */
    public static BigDecimal toBigDecimal(Object source) {
        return toBigDecimal(source, null);
    }

    // 假设这里补上了 convert 方法，因为前面代码调用了该方法但未定义
    private static <T> T convert(Class<T> targetType, Object source, T defValue) {
        // 这里可以添加具体的转换逻辑
        return defValue;
    }

    private static <T> T[] convert(Class<T[]> targetType, Object source) {
        // 这里可以添加具体的转换逻辑
        return null;
    }
}